﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace CMS.Common {
	/// <summary>
	/// CAPTCHA 验证码
	/// ( Completely Automated Public Turing test to Tell Computers and Humans Apart )
	/// </summary>
	public class Captcha {

		#region properties

		/// <summary>
		/// 获取图片效验码的固定高度
		/// </summary>
		/// <returns></returns>
		public static double GetImageHeight() {
			return 21.0;
		}

		/// <summary>
		/// 获取图片效验码的宽度
		/// </summary>
		/// <param name="validateNumLength">用于生成图片效验码的字符串长度</param>
		/// <returns></returns>
		public static int GetImageWidth(int validateNumLength) {
			return (validateNumLength * 13);
		}

		/// <summary>
		/// 获取效验码的最大长度
		/// </summary>
		public int MaxLength {
			get {
				return 10;
			}
		}

		/// <summary>
		/// 获取效验码的最小长度
		/// </summary>
		public int MinLength {
			get {
				return 1;
			}
		}

		#endregion

		#region methods

		/// <summary>
		/// 生成全数字的随机字符串
		/// </summary>
		/// <param name="length"></param>
		/// <returns></returns>
		public static string CreateNumericCaptcha(int length) {
			char[] charArray = "0123456789".ToCharArray();
			return CreateCaptcha(charArray, length);
		}

		/// <summary>
		/// 生成全字符的随机字符串
		/// </summary>
		/// <param name="length"></param>
		/// <returns></returns>
		public static string CreateCharacterCaptcha(int length) {
			char[] charArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
			return CreateCaptcha(charArray, length);
		}

		/// <summary>
		/// 生成包含数字和字符的随机字符串
		/// </summary>
		/// <param name="length"></param>
		/// <returns></returns>
		public static string CreateCaptcha(int length) {
			char[] charArray = "023456789ABCDEFGHJKLMNPQRSTUVWXYZ".ToCharArray();
			return CreateCaptcha(charArray, length);
		}

		/// <summary>
		/// 生成随机字符串的文字格式的效验码
		/// </summary>
		/// <param name="strArray">用于生成效验码的字符集合</param>
		/// <param name="length">效验码字符位数</param>
		/// <returns></returns>
		public static string CreateCaptcha(char[] charArray, int length) {
			string captcha = "";
			int num = -1;

			Random random = new Random();

			for (int i = 1; i < (length + 1); i++) {
				if (num != -1) {
					random = new Random((i * num) * ((int)DateTime.Now.Ticks));
				}

				int index = random.Next(30);

				if ((num != -1) && (num == index)) {
					return CreateCaptcha(length);
				}

				num = index;
				captcha = captcha + charArray[index];
			}
			return captcha;
		}

		/// <summary>
		/// 生成指定字符串的图片格式的效验码
		/// </summary>
		/// <param name="validateNum">用于生成图片的字符串</param>
		public static MemoryStream CreateImage(string validateNum) {
			// 创建位图 length * 13.5
			Bitmap image = new Bitmap((int)Math.Ceiling((double)(validateNum.Length * 13.5)), 20);
			Graphics graphics = Graphics.FromImage(image);

			try {
				Random random = new Random();
				graphics.Clear(Color.White);

				// 画图片的背景噪点
				for (int i = 0; i < 20; i++) {
					int x1 = random.Next(image.Width);
					int x2 = random.Next(image.Width);
					int y1 = random.Next(image.Height);
					int y2 = random.Next(image.Height);
					graphics.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
				}

				// 字体大小
				Font font = new Font("Arial", 12f, FontStyle.Italic | FontStyle.Bold);

				// 线性渐变封装
				LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
				graphics.DrawString(validateNum, font, brush, (float)3f, (float)2f);

				// 画图片的前景噪点
				for (int i = 0; i < 50; i++) {
					int x = random.Next(image.Width);
					int y = random.Next(image.Height);
					image.SetPixel(x, y, Color.FromArgb(random.Next()));
				}

				// 画图片的边框线 矩形
				graphics.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);

				// 创建其支持存储区为内存的
				MemoryStream stream = new MemoryStream();
				image.Save(stream, ImageFormat.Jpeg);

				return stream;
			}
			finally {
				graphics.Dispose();
				image.Dispose();
			}
		}

		#endregion
	}
}
